package com.esdk.sql.orm;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.esdk.esdk;

import java.time.LocalDateTime;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;

public class RowSetUtils{

	public static String[] Keywords=new String[]{
		"rows",
		"firstRow",
		"lastRow",
		"cursor",
		"columns",
		"getRows",
		"getFirstRow",
		"getLastRow",
		"getCursor",
		"getColumns",
		"currentRow",
		"getCurrentRow",
	};

	public static ABRowSet filter(IReadRowSet rowSet,IRowFilter filter) {
  	return filter(rowSet,filter,Integer.MAX_VALUE);
  }

	public static ABRowSet filter(IReadRowSet rowSet,IRowFilter filter,int top) {
  	ArrayList result=new ArrayList();
  	if(filter instanceof ITopable)
  		top=((ITopable)filter).getTop()==0?Integer.MAX_VALUE:((ITopable)filter).getTop();
  	for(int i=0;result.size()<top&&i<rowSet.size();i++) {
  		IRow row=rowSet.getRow(i);
  		boolean pass=filter.filter(row,rowSet,i);
  		if(pass)
  			result.add(row);
  	}
  	return new ABRowSet(rowSet,result);
  }

	public static ABRowSet sortById(ParentResultSet prs,Integer[] ids) {
		ABRowSet result=new ABRowSet(prs.getColumns());
		for(int i=0;i<ids.length;i++) {
			result.add(prs.findById(ids[i]));
		}
		return result;
	}

	static ABRowSet distinct(ABRowSet rowSet,String...fieldNames){
		if(fieldNames.length==0){
			return rowSet;
		}else{
			HashSet set=new HashSet(rowSet.size());
			for(int i=0;i<rowSet.size();i++){
				IRow row=(IRow)rowSet.getRow(i);
				StringBuilder key=new StringBuilder();
				for(int j=0;j<fieldNames.length;j++){
					key.append((row.get(fieldNames[j]))+"+");
				}
				if(set.contains(key.toString())){
					rowSet.remove(i);//注意不能使用remove(Collection)
					i--;
				}else
					set.add(key.toString());
			}
		}
		return rowSet;
	}

	/**
	 * 得到某个字段的所有记录的内容
	 * @param isDistinct 为了达到默认参数的效果，所以用动态参数方式解决，但只能解决一个默认参数
	 * */
	public static <T,R extends IRow> T[] getValues(List<R> list,String columnName,Class<T> cls,boolean isDistinct) {
		return esdk.array.toArray(getValues(list,columnName,isDistinct),cls);
	}

	public static <T,R extends IRow> T[] getValues(List<R> list,String columnName,Class<T> cls) {
		return esdk.array.toArray(getValues(list,columnName,false),cls);
	}

	/**得到某个字段的所有记录的内容 性能杠杠的*/
	public static <T,R extends IRow> List<T> getValues(List<R> list,String columnName,boolean isDistinct) {
		if(isDistinct){
			HashSet result=new HashSet();
			for (IRow row : list) {
				result.add(row.get(columnName));
			}
			return new ArrayList(result);
		}else{
			ArrayList result = new ArrayList();
			for (IRow row : list) {
				result.add(row.get(columnName));
			}
			return result;
		}
	}

	/**把重复的记录删除。注意，保留第一条未重复的记录，删除的第二条及之后的重复记录，返回的是已删除的记录集，TODO：用removeRedundant还是removeRepeat好呢？*/
	static IRowSet removeRepeat(IRowSet rowSet,String...fieldNames){
		ABRowSet result=new ABRowSet(rowSet.getColumns());
		if(fieldNames.length==0){
			return result;
		}else{
			HashSet set=new HashSet(rowSet.size());
			for(int i=0;i<rowSet.size();i++){
				IRow row=(IRow)rowSet.getRow(i);
				StringBuilder key=new StringBuilder();
				for(int j=0;j<fieldNames.length;j++){
					key.append((row.get(fieldNames[j]))+"+");
				}
				if(set.contains(key.toString())){
					result.add(row);
					rowSet.remove(i);//注意不能使用remove(Collection)
					i--;
				}else
					set.add(key.toString());
			}
		}
		return result;
	}

	static <T extends IRow> List<ABRowSet<T>> group(IReadRowSet<T> rowSet,String... fieldNames) {
		ArrayList<ABRowSet<T>> result=new ArrayList();
		if(fieldNames.length==0)
			result.add(new ABRowSet(rowSet));
		else
			result.addAll(groupMap(rowSet,fieldNames).values());
		return result;
	}

	static <T extends IRow> List<ABRowSet<T>> group(IReadRowSet<T> rowSet,Function fn) {
		return new ArrayList<>(groupMap(rowSet,fn).values());
	}

	static <T extends IRow> Map<?,ABRowSet<T>> groupMap(IReadRowSet<T> rowSet,String[] fieldNames) {
		LinkedHashMap<String,ABRowSet<T>> resultMap=new LinkedHashMap();
		for(T row:rowSet.getRows()){
			String key=esdk.str.listToStr(row.toList(fieldNames));
			ABRowSet rs=esdk.map.getVal(resultMap,key,()->new ABRowSet(rowSet,false));
			rs.addLast(row);
		}
		return resultMap;
	}

	static <T extends IRow> Map<?,ABRowSet<T>> groupMap(IReadRowSet<T> rowSet,Function<T,?> fn) {
		LinkedHashMap<Object,ABRowSet<T>> resultMap=new LinkedHashMap();
		for(T row:rowSet){
			Object key=esdk.obj.ifNull(fn.apply(row),"");
			ABRowSet abrs=esdk.map.getVal(resultMap,key,()->row instanceof ParentRow pr?new ABRowSet(pr.getClass()):new ABRowSet<>(row.getColumns()));
			abrs.addLast(row);
		}
		return resultMap;
	}


	public static List<ABRowSet<IRow>> split(IRowSet rowSet,int maxSize) {
		ArrayList<ABRowSet<IRow>> result=new ArrayList();
		ABRowSet abrs=new ABRowSet(rowSet.getColumns());
		for(int i=0,n=rowSet.size();i<n;i++) {
			IRow row=rowSet.getRow(i);
			abrs.add(row);
			if((i+1)%maxSize==0||i==n-1){
				result.add(abrs);
				abrs=new ABRowSet(rowSet.getColumns());
			}
		}
		return result;
  }

	public static RowFilter createRowFilter(String key,Object value){
		return RowFilter.create(key,value);
	}
	public static RowFilter createRowFilter(String key,String expr,Object value){
		return RowFilter.create(key,expr,value);
	}
	public static RegexRowFilter createRegexRowFilter(String regex){
		return new RegexRowFilter(regex);
	}
	public static RegexRowFilter createRegexRowFilter(String regex,boolean caseInsensitive,String... fields){
		return new RegexRowFilter(regex,caseInsensitive,fields);
	}
	//全文搜索过滤器
	public static FullTextRowFilter createFullTextRowFilter(String search){
		return new FullTextRowFilter(search);
	}
	public static FullTextRowFilter createFullTextRowFilter(String search,boolean ignoreCase,String... fields){
		return new FullTextRowFilter(search,ignoreCase,fields);
	}

	public static ABRowSet formatBoolean(IRowSet rs,String trueFormat,String falseFormat,String... fields){
		ArrayList result=new ArrayList();
		for(int i=0;i<rs.size();i++) {
  		IRow row=rs.getRow(i);
  		for(int j=0;j<fields.length;j++) {
  			if(((Boolean)row.get(fields[j]))) {
  				row.put(fields[j],trueFormat);
  			}else {
  				row.put(fields[j],falseFormat);
  			}
  		}
  		result.add(row);
		}
		return new ABRowSet(result);
	}

	/**删除空格，一般用于excel导入*/
	public static ABRowSet trim(ABRowSet rs) {
		for(Iterator iter=rs.iterator();iter.hasNext();) {
			IRow row=(IRow)iter.next();
			esdk.map.trim(row.record());
		}
		return rs;
	}

	/**删除空行，一般用于excel导入*/
	public static void deleteEmptyRows(ABRowSet rs){
		for(rs.beforeFirst();rs.next();) {
			if(!RowUtils.hasContent(rs.getCurrentRow())) {
				rs.remove(rs.getCurrentRow());
				rs.previous();
			}
		}
	}

	public static JSONArray toJsonArray(List<Map> rowsetMap,boolean isCamelCase){
		return toJsonArray(rowsetMap,isCamelCase,true);
	}

	/**解决Long值转到前端js会丢失精度的问题，会把Long转换为字符串*/
	public static JSONArray toJsonArray(List<Map> rowsetMap,boolean isCamelCase,boolean ifSnowIdToStr){
		JSONArray result=new JSONArray(rowsetMap.size());
		for(Iterator iter=rowsetMap.iterator();iter.hasNext();){
			Map map=(Map)iter.next();
			JSONObject jo=new JSONObject(true);
			for(Iterator iter1=map.entrySet().iterator();iter1.hasNext();) {
				Entry<String,Object> entry=(Entry)iter1.next();
				Object value=entry.getValue();
				if(value!=null){
					if(ifSnowIdToStr&&esdk.sql.isSnowId(value))
						value=value.toString();
					else if(value instanceof LocalDateTime)
						value=esdk.time.toDate((LocalDateTime)value);
					else if(value instanceof IResultSet)
						value=((IResultSet<?>)value).toJsonArray(true,true);
					else if(value instanceof IRow<?>)
						value=((IRow<?>)value).toJsonObject(true);
					jo.put(isCamelCase?esdk.str.toCamelCase(entry.getKey()):entry.getKey(),value);
				}
			}
			result.add(jo);

		}
		return result;
	}

	public static <T extends IRow> ABRowSet<T> join(T... rows){
		return new ABRowSet<T>(rows);
	}

	public static <T extends IRow> T getNextRow(ARowSet rs,T row){
		return (T)rs.getRow(rs.indexOf(row)+1);
	}

	public static <T extends IRow> T getBeforeRow(ARowSet rs,T row){
		return (T)rs.getRow(rs.indexOf(row)-1);
	}

}
